﻿using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;
using System.IO;

using EdgeStatz.ESSystems.Objects;

namespace EdgeStatz.ModelEngine.FormTools
{
    public class TabGenerator
    {
        TextWriter writer = null;

        List<CodeStatement> init_component = new List<CodeStatement> { };
        List<CodeStatement> setup_component = new List<CodeStatement> { };
        List<string> column_list = new List<string> { };

        CodeCompileUnit cu = new CodeCompileUnit();
        CodeNamespace cn = new CodeNamespace("EdgeStatz.GeneratedForms");
        CodeTypeDeclaration ctd = null;

        string classname;
        string foldername;

        int tabindex = 0;

        public TabGenerator(string classname, string foldername)
        {
            this.classname = classname;
            this.foldername = foldername;

            writer = new StreamWriter(GlobalSystemSettings.SystemFolderPath +
                (GlobalSystemSettings.SystemFolderPath.EndsWith("\\") ? "" : "\\") + classname + "_Form.cs", false);

            ctd = new CodeTypeDeclaration(classname);
            ctd.BaseTypes.Add(new CodeTypeReference(typeof(System.Windows.Forms.UserControl)));
            ctd.BaseTypes.Add(new CodeTypeReference(typeof(EdgeStatz.ESSystems.Objects.GeneratedTab)));

            AddImport("System");
            AddImport("System.Windows.Forms");
            AddImport("System.Drawing");

            AddImport("EdgeStatz.ESSystems.Objects");

            CodeConstructor constructor = new CodeConstructor();
            constructor.Attributes = MemberAttributes.Public;
            constructor.Statements.Add(new CodeMethodInvokeExpression(
                new CodeThisReferenceExpression(),
                    "InitializeComponent", new CodeExpression[] { }));

            ctd.Members.Add(constructor);
        }

        public void AddImport(string namespace_value)
        {
            cn.Imports.Add(new CodeNamespaceImport(namespace_value));
        }
        
        private void AddConstructor_LoadValues()
        {
            CodeConstructor constructor2 = new CodeConstructor();
            constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object[]), "array"));
            constructor2.Attributes = MemberAttributes.Public;
            constructor2.ChainedConstructorArgs.Add(new CodeSnippetExpression());
            int i = 0;
            List<CodeStatement> loopstatements = new List<CodeStatement> { };
            
            loopstatements.Add(new CodeVariableDeclarationStatement(typeof(object[]),
                "data",new CodeCastExpression(typeof(object[]),new CodeArrayIndexerExpression(new CodeVariableReferenceExpression(
                    "array"),new CodeVariableReferenceExpression("i")))));
            loopstatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "Rows"), "Add", new CodeExpression[] { })));

            foreach (string name in column_list.ToArray())
            {
                loopstatements.Add(new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeArrayIndexerExpression(new CodePropertyReferenceExpression(
                        new CodeArrayIndexerExpression(new CodePropertyReferenceExpression(
                            new CodeVariableReferenceExpression("_dataGridView"),"Rows"),new CodeExpression[]{
                                new CodeVariableReferenceExpression("i")}),"Cells"),new CodeExpression[]{new CodePrimitiveExpression(i)}),"Value")
                    , new CodeMethodInvokeExpression(new CodeArrayIndexerExpression(new CodeVariableReferenceExpression("data"), new CodeExpression[]{
                        new CodePrimitiveExpression(i)}),"ToString",new CodeExpression[]{}))); 
                i++;
            }
            constructor2.Statements.Add(new CodeIterationStatement(new CodeVariableDeclarationStatement(
                typeof(int), "i", new CodePrimitiveExpression(0)), new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
                    CodeBinaryOperatorType.LessThan, new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("array"), "Length")),
                    new CodeAssignStatement(new CodeVariableReferenceExpression("i"), new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
                        CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1))),loopstatements.ToArray()));


            ctd.Members.Add(constructor2);
        }

        private void AddSaveMethod()
        {
            CodeMemberMethod cmm_save = new CodeMemberMethod();
            cmm_save.Name = "Save";
            cmm_save.ReturnType = new CodeTypeReference(typeof(object[]));
            cmm_save.Attributes = MemberAttributes.Public;
            //List<CodeExpression> itemlist = new List<CodeExpression> { };
            //foreach (string name in component_list.ToArray())
            //{
            //    switch ((string)name.Split('_').GetValue(0))
            //    {
            //        case "cb":
            //            itemlist.Add(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(name), "SelectedValue"));
            //            break;
            //        case "nud":
            //            itemlist.Add(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(name), "Value"));
            //            break;
            //        case "chkb":
            //            itemlist.Add(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(name), "Checked"));
            //            break;
            //        case "dtp":
            //            itemlist.Add(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(name), "Value"));
            //            break;
            //        case "tb":
            //            itemlist.Add(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression(name), "Text"));
            //            break;
            //    }
            //}
            //cmm_save.Statements.Add(new CodeMethodReturnStatement(
            //    new CodeArrayCreateExpression(typeof(object), itemlist.ToArray())));
            cmm_save.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression()));
            ctd.Members.Add(cmm_save);
        }

        public FormDefinition WriteSourceCode()
        {
            AddConstructor_LoadValues();
            AddMethod_InitializeComponent();
            AddSaveMethod();

            cn.Types.Add(ctd);
            cu.Namespaces.Add(cn);

            Microsoft.CSharp.CSharpCodeProvider provider = new Microsoft.CSharp.CSharpCodeProvider();
            System.CodeDom.Compiler.CodeGeneratorOptions options = new System.CodeDom.Compiler.CodeGeneratorOptions();

            provider.GenerateCodeFromCompileUnit(cu, writer, options);

            writer.Close();

            return new FormDefinition(classname, foldername, GlobalSystemSettings.SystemFolderPath +
                (GlobalSystemSettings.SystemFolderPath.EndsWith("\\") ? "" : "\\") + classname + "_Form.cs",
                new string[] { "System.dll", "System.Drawing.dll", "System.Windows.Forms.dll", "EdgeStatz.ESSystems.dll" },new string[]{});
        }

        private void AddMethod_InitializeComponent()
        {
            CodeMemberMethod cmm_init = new CodeMemberMethod();
            cmm_init.Name = "InitializeComponent";
            cmm_init.ReturnType = new CodeTypeReference(typeof(void));

            ctd.Members.Add(new CodeMemberField(typeof(System.Windows.Forms.DataGridView), "_dataGridView"));
            init_component.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("_dataGridView"),
                new CodeObjectCreateExpression(typeof(System.Windows.Forms.DataGridView), new CodeExpression[] { })));

            cmm_init.Statements.AddRange(init_component.ToArray());

            cmm_init.Statements.Add(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(),
                "SuspendLayout", new CodeExpression[] { }));

            cmm_init.Statements.Add(new CodeCommentStatement(""));
            cmm_init.Statements.Add(new CodeCommentStatement("_dataGridView"));
            cmm_init.Statements.Add(new CodeCommentStatement(""));

            cmm_init.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "ColumnHeadersHeightSizeMode"), new CodeFieldReferenceExpression(
                    new CodeTypeReferenceExpression(typeof(System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode)),"AutoSize")));
            List<CodeExpression> colnamelist = new List<CodeExpression> { };

            foreach (string listitem in column_list)
            {
                colnamelist.Add(new CodeVariableReferenceExpression(listitem));
            }

            cmm_init.Statements.Add(new CodeMethodInvokeExpression(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "Columns"), "AddRange", new CodeExpression[] { 
                    new CodeArrayCreateExpression(typeof(System.Windows.Forms.DataGridViewColumn), colnamelist.ToArray())}));

            cmm_init.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "Dock"), new CodeFieldReferenceExpression(
                    new CodeTypeReferenceExpression(typeof(System.Windows.Forms.DockStyle)), "Fill")));
            cmm_init.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "Name"), new CodePrimitiveExpression("_dataGridView")));
            cmm_init.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "AutoSize"), new CodePrimitiveExpression(true)));
            cmm_init.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "TabIndex"), new CodePrimitiveExpression(0)));
            cmm_init.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "AllowUserToAddRows"), new CodePrimitiveExpression(false)));
            cmm_init.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "AllowUserToDeleteRows"), new CodePrimitiveExpression(false)));
            cmm_init.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("_dataGridView"), "AutoSizeColumnsMode"), new CodePropertyReferenceExpression(
                    new CodeTypeReferenceExpression(typeof(System.Windows.Forms.DataGridViewAutoSizeColumnsMode)),"Fill")));

            cmm_init.Statements.AddRange(setup_component.ToArray());

            cmm_init.Statements.Add(new CodeCommentStatement(""));
            cmm_init.Statements.Add(new CodeCommentStatement(classname));
            cmm_init.Statements.Add(new CodeCommentStatement(""));

            cmm_init.Statements.Add(new CodeMethodInvokeExpression(new CodeFieldReferenceExpression(
                new CodeThisReferenceExpression(), "Controls"), "Add", new CodeExpression[] { new CodeVariableReferenceExpression("_dataGridView") }));
            cmm_init.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(
                new CodeThisReferenceExpression(), "Name"), new CodePrimitiveExpression(foldername)));
            setup_component.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(
                new CodeThisReferenceExpression(), "Size"), new CodeObjectCreateExpression(typeof(System.Drawing.Size),
                    new CodeExpression[] { new CodePrimitiveExpression(750), new CodePrimitiveExpression(600) })));

            cmm_init.Statements.Add(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(),
                "ResumeLayout", new CodeExpression[] { new CodePrimitiveExpression(false) }));
            cmm_init.Statements.Add(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(),
                "PerformLayout", new CodeExpression[] { }));

            ctd.Members.Add(cmm_init);
        }

        public void AddColumn_TextBox(string name) 
        {
            ctd.Members.Add(new CodeMemberField(typeof(System.Windows.Forms.DataGridViewTextBoxColumn), "tbcol_" + name));

            init_component.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("tbcol_" + name),
                new CodeObjectCreateExpression(typeof(System.Windows.Forms.DataGridViewTextBoxColumn), new CodeExpression[] { })));

            setup_component.Add(new CodeCommentStatement(""));
            setup_component.Add(new CodeCommentStatement("tbcol_" + name));
            setup_component.Add(new CodeCommentStatement(""));
            column_list.Add("tbcol_" + name);

            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("tbcol_" + name), "Name"), new CodePrimitiveExpression("tbcol_" + name)));
            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("tbcol_" + name), "HeaderText"), new CodePrimitiveExpression(name)));
        }
        public void AddColumn_CheckBox(string name) 
        {
            ctd.Members.Add(new CodeMemberField(typeof(System.Windows.Forms.DataGridViewCheckBoxColumn), "chkbcol_" + name));

            init_component.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("chkbcol_" + name),
                new CodeObjectCreateExpression(typeof(System.Windows.Forms.DataGridViewCheckBoxColumn), new CodeExpression[] { })));

            setup_component.Add(new CodeCommentStatement(""));
            setup_component.Add(new CodeCommentStatement("chkbcol_" + name));
            setup_component.Add(new CodeCommentStatement(""));
            column_list.Add("chkbcol_" + name);

            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("chkbcol_" + name), "Name"), new CodePrimitiveExpression("chkbcol_" + name)));
            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("chkbcol_" + name), "HeaderText"), new CodePrimitiveExpression(name)));
        }
        public void AddColumn_Combobox(string name)
        {
            ctd.Members.Add(new CodeMemberField(typeof(System.Windows.Forms.DataGridViewComboBoxColumn), "cbcol_" + name));

            init_component.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("cbcol_" + name),
                new CodeObjectCreateExpression(typeof(System.Windows.Forms.DataGridViewComboBoxColumn), new CodeExpression[] { })));

            setup_component.Add(new CodeCommentStatement(""));
            setup_component.Add(new CodeCommentStatement("cbcol_" + name));
            setup_component.Add(new CodeCommentStatement(""));
            column_list.Add("cbcol_" + name);

            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("cbcol_" + name), "Name"), new CodePrimitiveExpression("cbcol_" + name)));
            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("cbcol_" + name), "HeaderText"), new CodePrimitiveExpression(name)));
        }
        public void AddColumn_Id(string name)
        {
            ctd.Members.Add(new CodeMemberField(typeof(System.Windows.Forms.DataGridViewTextBoxColumn), "idcol_" + name));

            init_component.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("idcol_" + name),
                new CodeObjectCreateExpression(typeof(System.Windows.Forms.DataGridViewTextBoxColumn), new CodeExpression[] { })));

            setup_component.Add(new CodeCommentStatement(""));
            setup_component.Add(new CodeCommentStatement("idcol_" + name));
            setup_component.Add(new CodeCommentStatement(""));
            column_list.Add("idcol_" + name);

            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("idcol_" + name), "Name"), new CodePrimitiveExpression("tbcol_" + name)));
            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("idcol_" + name), "HeaderText"), new CodePrimitiveExpression(name)));
            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("idcol_" + name), "Visible"), new CodePrimitiveExpression(false)));
            setup_component.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("idcol_" + name), "ReadOnly"), new CodePrimitiveExpression(true)));
        }

        public void AddDefaultValues(string name, string foreigntable, string display, string value)
        {
            CodeMemberMethod cmm_adddef = new CodeMemberMethod();
            cmm_adddef.Name = "AddDefaultValues_" + name;
            cmm_adddef.ReturnType = new CodeTypeReference(typeof(void));
            CodeConstructor cons = (CodeConstructor)ctd.Members[0];
            cons.Statements.Add(
                new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "AddDefaultValues_" + name, new CodeExpression[] { }));
            ctd.Members[0] = cons;

            cmm_adddef.Statements.Add(new CodeVariableDeclarationStatement(typeof(object[]), "returndata",
                new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(
                    "GlobalObjectsSQL"), "ExecuteSingleTableRead",
                    new CodeExpression[]{new CodeArrayCreateExpression(typeof(string),new CodeExpression[]{
                        new CodePrimitiveExpression(display), new CodePrimitiveExpression(value)}), 
                        new CodePrimitiveExpression(foreigntable),new CodePrimitiveExpression("")})));
            cmm_adddef.Statements.Add(new CodeMethodInvokeExpression(
                new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("cbcol_" + name), "Items"),
                "Clear", new CodeExpression[] { }));

            List<CodeStatement> loopstatements = new List<CodeStatement> { };
            loopstatements.Add(new CodeVariableDeclarationStatement(typeof(object[]), "data",
                new CodeCastExpression(typeof(object[]), new CodeArrayIndexerExpression(
                    new CodeVariableReferenceExpression("returndata"), new CodeExpression[] { new CodeVariableReferenceExpression("i") }))));
            
            loopstatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("cbcol_" + name), "Items"), "Add",
                new CodeObjectCreateExpression(typeof(EdgeStatz.ESSystems.Objects.DisplayValueObject),
                new CodeExpression[] {new CodeMethodInvokeExpression(new CodeArrayIndexerExpression(new CodeVariableReferenceExpression("data"), 
                    new CodeExpression[]{new CodePrimitiveExpression(0)}),"ToString",new CodeExpression[]{}), new CodeMethodInvokeExpression(
                        new CodeCastExpression(typeof(System.Guid),new CodeArrayIndexerExpression(new CodeVariableReferenceExpression("data"),
                            new CodeExpression[]{new CodePrimitiveExpression(1)})),"ToString",new CodeExpression[]{})}))));
            
            cmm_adddef.Statements.Add(new CodeIterationStatement(
                new CodeVariableDeclarationStatement(typeof(int), "i", new CodePrimitiveExpression(0)),
                new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan,
                    new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("returndata"), "Length")),
                new CodeAssignStatement(new CodeVariableReferenceExpression("i"), new CodeBinaryOperatorExpression(
                    new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1))),
                loopstatements.ToArray()));
            
            cmm_adddef.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("cbcol_" + name), "DisplayMember"), new CodePrimitiveExpression("Display")));
            
            cmm_adddef.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(
                new CodeVariableReferenceExpression("cbcol_" + name), "ValueMember"), new CodePrimitiveExpression("Value")));

            ctd.Members.Add(cmm_adddef);
        }
    }
}
